import { EraserMode, EraserShapeMode } from './enums';
import { InnerCanvas } from './innercanvas';
import { Point } from '../geometry/point';
import { EraserShape, RectEraserShape, EllipseEraserShape } from './erasershape';
import { Stroke } from './stroke';
import { InkSettings } from './inksetting';
import { GUtils } from '../geometry/gutils';
import { EventBase } from '../eventbase';
import { EventNames } from './eventnames';

export class EraserProcessor extends EventBase {
    /**橡皮擦擦除模式 */
    private _eraserMode = EraserMode.Line;
    /**橡皮形状模式 */
    private _eraserShapeMode = EraserShapeMode.Rect;
    /**橡皮擦形状款高度 */
    private _eraserWidth: number = 10;
    private _eraserShape: EraserShape;
    /**画板 */
    private _canvas: HTMLCanvasElement;
    /**InnerCanvas实例 */
    private _innerCanvas: InnerCanvas;
    /**鼠标或触控设备最后操作点 */
    private _lastPoint: Point;
    /**鼠标或触控移动处理 */
    private onMouseOrTouchMove = (event: MouseEvent | TouchEvent) => { this.mouseOrTouchMove(event); };
    /**鼠标或触控释放处理 */
    private onMouseOrTouchOut = (event: MouseEvent | TouchEvent) => { this.mouseOrTouchOut(event); };

    /**
     * 构造函数
     * @param innerCanvas 
     * @param canvas 
     * @param eraserMode 
     * @param eraserShapeMode 
     * @param eraserWidth 
     */
    constructor(innerCanvas: InnerCanvas, canvas: HTMLCanvasElement, eraserMode: EraserMode = EraserMode.Line
        , eraserShapeMode: EraserShapeMode = EraserShapeMode.Rect, eraserWidth: number = 20) {
        super();
        this._innerCanvas = innerCanvas;
        this._canvas = canvas;
        this._eraserWidth = eraserWidth;
        this._eraserMode = eraserMode;
        this._eraserShapeMode = eraserShapeMode;
        this.refreshEraserShape();
    }
    /**
     * 获取或设置橡皮擦擦除模式
     */
    public get eraserMode() {
        return this._eraserMode;
    }
    public set eraserMode(value: EraserMode) {
        if (this._eraserMode !== value) {
            this._eraserMode = value;
        }
    }
    /**
     * 获取或设置橡皮形状模式
     */
    public get eraserShapeMode() {
        return this._eraserShapeMode;
    }
    public set eraserShapeMode(value: EraserShapeMode) {
        if (this._eraserShapeMode !== value) {
            this._eraserShapeMode = value;
            this.refreshEraserShape();
        }
    }
    /**
     * 获取或设置橡皮形状宽度
     */
    public get eraserWidth() {
        return this._eraserWidth;
    }
    public set eraserWidth(value: number) {
        if (this._eraserWidth !== value) {
            this._eraserWidth = value;
            this.refreshEraserShape();
        }
    }

    //#region 私有方法
    /**
     * 激活橡皮擦处理器
     * @param _event 
     */
    public active(_event: MouseEvent | TouchEvent) {
        let touch: Touch, source: any = null, currentPoint = null;
        if (_event instanceof MouseEvent) {
            source = _event;
        } else if (_event instanceof TouchEvent) {
            source = touch = _event.touches[0];
        }
        currentPoint = new Point(source.clientX, source.clientY);
        currentPoint = this._innerCanvas.clientPointToCanvasPoint(currentPoint);
        this._lastPoint = currentPoint;
        this.attachEvent();
    }
    /**
     * 禁用橡皮擦处理器
     * @param _event 
     */
    public deactive(_event: MouseEvent | TouchEvent) {
        this.deattachEvent();
    }
    /**
     * 事件订阅
     */
    private attachEvent() {
        const canvas = this._canvas;
        this.deattachEvent();
        if (canvas) {
            canvas.addEventListener('mousemove', this.onMouseOrTouchMove);
            canvas.addEventListener('mouseup', this.onMouseOrTouchOut);
            canvas.addEventListener('mouseout', this.onMouseOrTouchOut);
            canvas.addEventListener('touchmove', this.onMouseOrTouchMove);
            canvas.addEventListener('touchend', this.onMouseOrTouchOut);
            canvas.addEventListener('touchcancel', this.onMouseOrTouchOut);
        }
    }
    /**
     * 取消事件订阅
     */
    private deattachEvent() {
        const canvas = this._canvas;
        if (canvas) {
            canvas.removeEventListener('mousemove', this.onMouseOrTouchMove);
            canvas.removeEventListener('mouseup', this.onMouseOrTouchOut);
            canvas.removeEventListener('mouseout', this.onMouseOrTouchOut);
            canvas.removeEventListener('touchmove', this.onMouseOrTouchMove);
            canvas.removeEventListener('touchend', this.onMouseOrTouchOut);
            canvas.removeEventListener('touchcancel', this.onMouseOrTouchOut);
        }
    }
    /**
     * 鼠标或触控设备移动处理
     * @param _event 
     */
    private mouseOrTouchMove(_event: MouseEvent | TouchEvent) {
        let touch: Touch | null = null, source: any = null, currentPoint: Point;
        if (_event instanceof MouseEvent) {
            source = _event;
        } else if (_event instanceof TouchEvent) {
            source = touch = _event.touches[0];
        }
        // 坐标转换
        currentPoint = new Point(source.clientX, source.clientY);
        currentPoint = this._innerCanvas.clientPointToCanvasPoint(currentPoint);

        // 删除处理
        const strokes = this._innerCanvas.strokes;
        if (this._eraserMode === EraserMode.Point) {
            this.proccessPointDelete(strokes, currentPoint);
        } else {
            this.proccessLineDelete(strokes, currentPoint);
        }

        // 记录最后操作点
        this._lastPoint = currentPoint;
    }
    /**
     * 鼠标或触控设备移开处理
     * @param _event 
     */
    private mouseOrTouchOut(_event: MouseEvent | TouchEvent) {
        this.deactive(_event);
    }
    /**
     * 处理点删操作
     * @param strokes 
     * @param currentPoint 
     */
    private proccessPointDelete(strokes: Stroke[], currentPoint: Point) {
        const geometry = this._eraserShape.getGeometry(currentPoint);
        const newStrokes: Stroke[] = [];
        for (let sIndex = 0; sIndex < strokes.length; sIndex++) {
            const stroke = strokes[sIndex];
            if (stroke.points.length === 1 ) {
                if (geometry.pointInThis(stroke.points[0])) {
                    newStrokes.push(stroke);
                    break;
                }
            } else {
                let lPoint = new Point();
                    for (let pIndex = 0; pIndex < stroke.points.length; pIndex++) {
                        if (pIndex > 0) {
                            const cPoint = stroke.points[pIndex];
                            const intersectPoints = geometry.getIntersectPoints(lPoint, cPoint);
                            if (intersectPoints.length > 0) {
                                console.log(intersectPoints);
                            }
                        }
                        lPoint = stroke.points[pIndex];
                    }
            }
            
        }
    }
    /**
     * 处理线删操作
     * @param strokes 
     * @param currentPoint 
     */
    private proccessLineDelete(strokes: Stroke[], currentPoint: Point) {
        const geometry = this._eraserShape.getGeometry(currentPoint);
        const newStrokes: Stroke[] = [];
        const deletedStrokes: Stroke[] = [];
        for (let sIndex = 0; sIndex < strokes.length; sIndex++) {
            let deleted = false;
            const stroke = strokes[sIndex];
            if (stroke.points.length === 1 ) {
                if (geometry.pointInThis(stroke.points[0])) {
                    deleted = true;
                    deletedStrokes.push(stroke);
                    break;
                }
            } else {
                let lPoint = new Point();
                    for (let pIndex = 0; pIndex < stroke.points.length; pIndex++) {
                        if (pIndex > 0) {
                            const cPoint = stroke.points[pIndex];
                            if (GUtils.isIntersect(this._lastPoint, currentPoint, lPoint, cPoint)) {
                                deleted = true;
                                deletedStrokes.push(stroke);
                                break;
                            }
                        }
                        lPoint = stroke.points[pIndex];
                    }
            }
            if (!deleted) {
                newStrokes.push(stroke);
            }
        }
        // 设置新的线条
        if (deletedStrokes && deletedStrokes.length > 0) {
            // 设置新的线条
            this._innerCanvas.strokes = newStrokes;

            // 事件通知
            this.publishEvent(EventNames.strokeDeletedEventName, {deletedStrokes: deletedStrokes});
        }
        
    }
    /**
     * 刷新橡皮擦形状
     */
    private refreshEraserShape() {
        if (this._eraserShapeMode === EraserShapeMode.Rect) {
            this._eraserShape = new RectEraserShape(this._eraserWidth, this._eraserWidth);
        } else {
            this._eraserShape = new EllipseEraserShape(this._eraserWidth, this._eraserWidth);
        }
    }
    //#endregion
}